<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>手写Vue响应式原理</h1>
    <script>
        /*
        原理: 
        data属性由Object.definedPropertype()建立getter,setter方法,进行响应式处理
        实现:
        1.基本数据类型实现响应式
        2.object和array类型实现响应式
        */
        /*        let data = {}
               let name = 'liang'
       
               Object.defineProperty(data,'name',{
                   get:function() {
                       return name
                   },
                   set:function(newValue) {
                       console.log('更新视图')
                       name = newValue
                   }
               })
       
               console.log(data.name)
               data.name = 'wang' */

        // 2.对象类型且有嵌套对象
        let data = {
            name: 'liang',
            age: 20,
            friends: {
                name: 'zhuge',
                age: 20
            },
            color: ['red', 'green', 'blue']
        }

        //操作Array函数
        const oldProto = Array.prototype
        const newProto = Object.create(Array.prototype)
        console.log(oldProto)
        console.log(newProto)
        //通过forEach给newProto添加这些函数
        ;['push','pop','shift','unshift','splice'].forEach(methodName => {
                //TODO 此处newProto.method和newProto[methodeName]的区别
            newProto[methodName] = function () {
                console.log('更新视图')
                oldProto[methodName].call(this,...arguments)
            }
        })
        //新的原型对象有了一些新的跟Array同名的属性
        console.log(newProto)


        observer(data)

        function observer(data) {
            //不是object类型的或者是null的都不再继续下面的解析,因为null typeof后也是object
            if (typeof data !== 'object' || data === null) {
                return data
            }
              //如果某个对象是数组,那么给这个数组赋值新的原型对象
            if (Array.isArray(data)) {
              data.__proto__ = newProto
            }

            for (let key in data) {
                // console.log('data',data)
                // console.log('key',key)
                // console.log('value',data[key])
                foo(data, key, data[key])
            }
        }

        function foo(data, key, value) {
            observer(value)
         
            //会直接在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回此对象。
            //核心思路就是,通过get/set函数对对象进行了拦截,并可以进行操作
            Object.defineProperty(data, key, {
                get() {
                    // console.log(value);
                    return value
                },
                set(newValue) {
                    //如果赋值的时候,添加的是object类型,那么对此数据再次进行观察.通过Object.defineProperty()将对象的属性重新定义,并获取
                    //getter,setter函数,进行操作
                    //getter中的操作:dom发生操作后,数据发生变化,在此获取value,进行处理变化,返回到对象中
                    //setter中:当对象的中的某一值发生变化时,setter函数获取到,可以将新的值在dom中进行操作
                    observer(newValue)
                    // data[key] = newValue
                    if (value !== newValue) {
                        value = newValue
                    }
                    console.log('视图更新');
                }
            })
        }
        // data.age = {   //赋一个对象类型的值 就是执行set函数
        //     number: 211
        // }
        // console.log(data.age.number)
        // data.color
            data.color.push('kk')



    </script>
</body>

</html>